package com.pan.config;

import com.pan.entity.ExecutiveInfo;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

public enum MappingConfig {
    INSTANCE;



    {
        flush();
    }
    private final String configFile = "mapping.xml";

    private Element rootElement;

    private Element getFirstElementByTagName(Element element, String name){
        NodeList nodeList = element.getElementsByTagName(name);
        for (int i = 0; i < nodeList.getLength(); i++) {
            Node node = nodeList.item(i);
            if (node.getNodeType() == Node.ELEMENT_NODE){
                return (Element) node;
            }
        }
        return null;
    }

    private List<Element> getElementsByTagName(Element element, String name){
        NodeList nodeList = element.getElementsByTagName(name);
        List<Element> list = new ArrayList<>();
        for (int i = 0; i < nodeList.getLength(); i++) {
            Node node = nodeList.item(i);
            if (node.getNodeType() == Node.ELEMENT_NODE){
                list.add((Element) node);
            }
        }
        return list;
    }


    public List<ExecutiveInfo> getExecutiveInfos(){
        Element executives = getFirstElementByTagName(rootElement, "executives");
        if (executives == null){
            throw new RuntimeException("Config Error: Not found Executives Tag");
        }
        List<Element> executiveList = getElementsByTagName(executives, "executive");
        return executiveList.stream().map(INSTANCE::parseExecutiveElement)
                .toList();
    }

    /**
     * 将xml标签转换为ExecutiveInfo 实体类
     * @param element
     * @return
     */
    private ExecutiveInfo parseExecutiveElement(Element element){
        if (!element.getTagName().equals("executive")){
            throw new RuntimeException("config error: "+element.getTagName()+" is not executive");
        }
        Element keyElement = getFirstElementByTagName(element, "key");
        if (keyElement == null){
            throw new RuntimeException("config error: key not found in executive item");
        }
        String key = keyElement.getTextContent().strip();

        Element typeElement = getFirstElementByTagName(element, "type");
        String type;
        if (typeElement == null) {
            type = "class";
        } else {
            type = typeElement.getTextContent().strip();
            if (!type.equals("class") && !type.equals("script")){
                throw new RuntimeException("config error: wrong type in executive, it can only be a class or script, but now it is "+type);
            }
        }

        Element nameElement = getFirstElementByTagName(element, "name");
        if (nameElement == null){
            throw new RuntimeException("config error: name not found in strategy item");
        }
        String name = nameElement.getTextContent().strip();
        ExecutiveInfo executiveInfo = new ExecutiveInfo(key,type,name);
        return executiveInfo;
    }


    public void flush() {
        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
        InputStream configStream = ClassLoader
                .getSystemResourceAsStream(configFile);
        try {
            DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
            Document document = documentBuilder.parse(configStream);
            document.normalizeDocument();
            rootElement = document.getDocumentElement();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    public static void main(String[] args) {
//        INSTANCE.getExecutiveInfos().forEach(System.out::println);
    }
}
